<!DOCTYPE html><html lang="zh-CN" data-theme="light"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width,initial-scale=1"><title>后端学习记录 - 随时随地记录知识</title><meta name="author" content="h0ss"><meta name="copyright" content="h0ss"><meta name="format-detection" content="telephone=no"><meta name="theme-color" content="#ffffff"><meta name="description" content="h0ss的后端学习记录">
<meta property="og:type" content="website">
<meta property="og:title" content="后端学习记录">
<meta property="og:url" content="https://blog.gpnusz.cn/index.html">
<meta property="og:site_name" content="后端学习记录">
<meta property="og:description" content="h0ss的后端学习记录">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://blog.gpnusz.cn/img/avatar.jpg">
<meta property="article:author" content="h0ss">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://blog.gpnusz.cn/img/avatar.jpg"><link rel="shortcut icon" href="/img/favicon.png"><link rel="canonical" href="https://blog.gpnusz.cn/"><link rel="preconnect" href="//cdn.jsdelivr.net"/><link rel="stylesheet" href="/css/index.css"><link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free/css/all.min.css" media="print" onload="this.media='all'"><script>const GLOBAL_CONFIG = { 
  root: '/',
  algolia: undefined,
  localSearch: undefined,
  translate: undefined,
  noticeOutdate: undefined,
  highlight: {"plugin":"highlighjs","highlightCopy":true,"highlightLang":true,"highlightHeightLimit":false},
  copy: {
    success: '复制成功',
    error: '复制错误',
    noSupport: '浏览器不支持'
  },
  relativeDate: {
    homepage: false,
    post: false
  },
  runtime: '天',
  date_suffix: {
    just: '刚刚',
    min: '分钟前',
    hour: '小时前',
    day: '天前',
    month: '个月前'
  },
  copyright: undefined,
  lightbox: 'fancybox',
  Snackbar: undefined,
  source: {
    jQuery: 'https://cdn.jsdelivr.net/npm/jquery@latest/dist/jquery.min.js',
    justifiedGallery: {
      js: 'https://cdn.jsdelivr.net/npm/justifiedGallery/dist/js/jquery.justifiedGallery.min.js',
      css: 'https://cdn.jsdelivr.net/npm/justifiedGallery/dist/css/justifiedGallery.min.css'
    },
    fancybox: {
      js: 'https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@latest/dist/jquery.fancybox.min.js',
      css: 'https://cdn.jsdelivr.net/npm/@fancyapps/fancybox@latest/dist/jquery.fancybox.min.css'
    }
  },
  isPhotoFigcaption: false,
  islazyload: false,
  isanchor: false
}</script><script id="config-diff">var GLOBAL_CONFIG_SITE = { 
  isPost: false,
  isHome: true,
  isHighlightShrink: false,
  isToc: false,
  postUpdate: '2022-11-16 01:31:32'
}</script><noscript><style type="text/css">
  #nav {
    opacity: 1
  }
  .justified-gallery img {
    opacity: 1
  }

  #recent-posts time,
  #post-meta time {
    display: inline !important
  }
</style></noscript><script>(win=>{
    win.saveToLocal = {
      set: function setWithExpiry(key, value, ttl) {
        if (ttl === 0) return
        const now = new Date()
        const expiryDay = ttl * 86400000
        const item = {
          value: value,
          expiry: now.getTime() + expiryDay,
        }
        localStorage.setItem(key, JSON.stringify(item))
      },

      get: function getWithExpiry(key) {
        const itemStr = localStorage.getItem(key)

        if (!itemStr) {
          return undefined
        }
        const item = JSON.parse(itemStr)
        const now = new Date()

        if (now.getTime() > item.expiry) {
          localStorage.removeItem(key)
          return undefined
        }
        return item.value
      }
    }
  
    win.getScript = url => new Promise((resolve, reject) => {
      const script = document.createElement('script')
      script.src = url
      script.async = true
      script.onerror = reject
      script.onload = script.onreadystatechange = function() {
        const loadState = this.readyState
        if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
        script.onload = script.onreadystatechange = null
        resolve()
      }
      document.head.appendChild(script)
    })
  
      win.activateDarkMode = function () {
        document.documentElement.setAttribute('data-theme', 'dark')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#0d0d0d')
        }
      }
      win.activateLightMode = function () {
        document.documentElement.setAttribute('data-theme', 'light')
        if (document.querySelector('meta[name="theme-color"]') !== null) {
          document.querySelector('meta[name="theme-color"]').setAttribute('content', '#ffffff')
        }
      }
      const t = saveToLocal.get('theme')
    
          if (t === 'dark') activateDarkMode()
          else if (t === 'light') activateLightMode()
        
      const asideStatus = saveToLocal.get('aside-status')
      if (asideStatus !== undefined) {
        if (asideStatus === 'hide') {
          document.documentElement.classList.add('hide-aside')
        } else {
          document.documentElement.classList.remove('hide-aside')
        }
      }
    })(window)</script><meta name="generator" content="Hexo 5.4.0"><link rel="stylesheet" href="/css/prism-tomorrow.css" type="text/css"></head><body><div id="web_bg"></div><div id="sidebar"><div id="menu-mask"></div><div id="sidebar-menus"><div class="author-avatar"><img class="avatar-img" src="/img/avatar.jpg" onerror="onerror=null;src='/img/friend_404.gif'" alt="avatar"/></div><div class="site-data"><div class="data-item is-center"><div class="data-item-link"><a href="/archives/"><div class="headline">文章</div><div class="length-num">51</div></a></div></div><div class="data-item is-center"><div class="data-item-link"><a href="/tags/"><div class="headline">标签</div><div class="length-num">14</div></a></div></div></div><hr/><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page" href="/archives/"><i class="fa-fw fas fa-archive"></i><span> 时间轴</span></a></div><div class="menus_item"><a class="site-page" href="/tags/"><i class="fa-fw fas fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="/categories/"><i class="fa-fw fas fa-folder-open"></i><span> 分类</span></a></div><div class="menus_item"><a class="site-page" href="/link/"><i class="fa-fw fas fa-link"></i><span> 友链</span></a></div><div class="menus_item"><a class="site-page" href="/about/"><i class="fa-fw fas fa-heart"></i><span> 关于</span></a></div></div></div></div><div class="page" id="body-wrap"><header class="not-top-img" id="page-header"><nav id="nav"><span id="blog_name"><a id="site-name" href="/">后端学习记录</a></span><div id="menus"><div class="menus_items"><div class="menus_item"><a class="site-page" href="/"><i class="fa-fw fas fa-home"></i><span> 首页</span></a></div><div class="menus_item"><a class="site-page" href="/archives/"><i class="fa-fw fas fa-archive"></i><span> 时间轴</span></a></div><div class="menus_item"><a class="site-page" href="/tags/"><i class="fa-fw fas fa-tags"></i><span> 标签</span></a></div><div class="menus_item"><a class="site-page" href="/categories/"><i class="fa-fw fas fa-folder-open"></i><span> 分类</span></a></div><div class="menus_item"><a class="site-page" href="/link/"><i class="fa-fw fas fa-link"></i><span> 友链</span></a></div><div class="menus_item"><a class="site-page" href="/about/"><i class="fa-fw fas fa-heart"></i><span> 关于</span></a></div></div><div id="toggle-menu"><a class="site-page"><i class="fas fa-bars fa-fw"></i></a></div></div></nav></header><main class="layout" id="content-inner"><div class="recent-posts" id="recent-posts"><div class="recent-post-item"><div class="recent-post-info no-cover"><a class="article-title" href="/2022/11/16/%E7%BB%99%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AE%E6%8F%90%E4%BA%86%E4%B8%AAPR/" title="给开源项目提了个PR">给开源项目提了个PR</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time datetime="2022-11-15T17:28:40.000Z" title="发表于 2022-11-16 01:28:40">2022-11-16</time></span></div><div class="content">拖了很久的文章终于动笔了，两个月前提的PR现在才开始写总结文章，lazydog一只….
1、背景首先介绍下 Sa-Token ，这是一个轻量级 Java 权限认证框架，主要解决：登录认证、权限认证、单点登录、OAuth2.0、分布式Session会话、微服务网关鉴权 等一系列权限相关问题。

优化源自其中的一个随机数获取逻辑实现，具体 PR 如图所示，该PR已被合并到主线代码中，在10月28日发布的 v1.32.0 中已经完成替换。

主要工作就是使用 ThreadLocalRadom 获取随机数去替换原来的 Random 获取，PR中也有给出具体的测试样例和数据来佐证更换之后的性能提升，但今天这篇文章还是想更全面地讲一下几种随机数获取逻辑的使用和性能差异。
2、随机数获取方式1）多例Random在 Java 中我们获取随机数自然而然会想到使用 Random 对象的 nextXX 方法去获取，这也是最简单的一种，例如可以这样：
123456789101112public class SaUtils1 &#123;    public static String getRandomStr ...</div></div></div><div class="recent-post-item"><div class="recent-post-info no-cover"><a class="article-title" href="/2022/09/03/%E3%80%90MySQL%E3%80%91InnoDB%E7%9A%84%E8%A1%8C%E6%A0%BC%E5%BC%8F/" title="【MySQL】InnoDB的行格式">【MySQL】InnoDB的行格式</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time datetime="2022-09-02T18:17:38.000Z" title="发表于 2022-09-03 02:17:38">2022-09-03</time></span></div><div class="content">1）数据存储形式首先明确在innodb引擎中数据是以页为基本单位读取的，而一个页中又包含多个行数据，那么对应地就会有不同的行格式来存储数据，innodb中的行格式有四种：compact、redundant、dynamic、compressed。redundant 是 5.0 之前用的行格式，这里就不记录了。
2）compact 行格式
可以看到 compact 行格式中将一行分成了两个部分，一个是真实数据的存储，一个是一些记录的信息。接下来一个一个看。
① 变长字段长度列表在MySQL中有char和varchar两种字符串类型，他们的区别是 varchar 是变长的类型，对于一列二进制流，我们通过变长字段长度列表就可以得到真实长度。
在这里会逆序地存储变长字段的真实长度，真实长度用1个/2个字节来存储，同时将长度的第一个二进制位作为标志符，如果为0则说明长度是1个字节，如果为1则说明长度是2个字节，这也就可以解释为什么varchar只能存储最大65535个字节，也解释了为什么真实长度在127以下就可以用一个字节存储。
这里不是说char类型就一定不会用到该列表，对于定长的字符集来说，c ...</div></div></div><div class="recent-post-item"><div class="recent-post-info no-cover"><a class="article-title" href="/2022/08/21/%E3%80%90Debug%E3%80%91bitField-%E5%BC%95%E5%8F%91%E7%9A%84%E6%A0%88%E6%BA%A2%E5%87%BA%E6%8E%92%E9%94%99%E8%AE%B0/" title="【Debug】bitField 引发的栈溢出排错记">【Debug】bitField 引发的栈溢出排错记</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time datetime="2022-08-20T18:10:40.000Z" title="发表于 2022-08-21 02:10:40">2022-08-21</time></span></div><div class="content">1、背景前期因为布隆过滤器的实现需求，导入了 redisson 的依赖，后面项目需求迭代，需要用到 redis 的 bitmap 来做签到信息的存储，并且需要提供读取每月签到记录的功能，这里需要用 bitField 方法将位信息读取成 Long 数值，之后进行移位操作得到当月每天的签到情况，问题代码如下：

对于 bit 的 set 操作是没问题的，但是用到这个 bitField 就出问题了。
项目的依赖版本信息如下：



依赖
版本



springboot
2.4.12


spring-data-redis
2.4.14


lettuce-core
6.0.8.RELEASE


redisson-spring-boot-starter
3.11.5


2、现象做单元测试的时候发现在 bitField 方法会栈溢出，看堆栈信息是递归调用自己了：

3、定位在图1的136行上打个断点debug看下，跟着 stringRedisTemplate.opsForValue() 方法可以来到 DefaultValueOperations 的 bitField 方法，398行是将ke ...</div></div></div><div class="recent-post-item"><div class="recent-post-info no-cover"><a class="article-title" href="/2022/07/16/%E3%80%90RPC%E3%80%91%E8%AF%A6%E8%A7%A3SPI%E6%9C%BA%E5%88%B6/" title="【RPC】详解SPI机制">【RPC】详解SPI机制</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time datetime="2022-07-15T18:51:57.000Z" title="发表于 2022-07-16 02:51:57">2022-07-16</time></span></div><div class="content">1、SPI 概念SPI 的全称叫做：Service Provider Interface，它是一种通过外界配置来加载具体代码内容的技术手段。在中间件设计中大多采用微内核+拓展组件的形式，SPI技术则是当前各款中间件都在主流使用的一项扩展技术，比如Dubbo内部的核心思想就是采用SPI扩展技术来实现可插拔式组件。
引入SPI技术的目的是希望可以通过配置化的方式来引入自定义插件部分，具体实现为在统一规定的文件目录底下新建一份文件，并在该文件内部定义好需要加载的类，让核心程序在不做内部源代码修改的条件下可以引入执行的代码逻辑。业界常见的SPI机制大体分为了两种类型：
① JDK内部自带的SPI机制；② 自定义实现的SPI机制。
2、Java SPI1）使用新建一个业务接口：

创建它的实现类（2同）：

在 META-INF/services 目录下创建名为接口全类名的文件，并写入实现类全类名：

接着测试一下，使用ServiceLoader的load方法生成对象：


2）原理JDK内部的ServiceLoader加载流程大致为：
调用load函数—&gt;调用reload方法—&gt;触 ...</div></div></div><div class="recent-post-item"><div class="recent-post-info no-cover"><a class="article-title" href="/2022/07/14/%E3%80%90Redis%E3%80%91%E9%87%8D%E8%A6%81%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%9F%BA%E7%A1%80/" title="【Redis】重要数据结构基础">【Redis】重要数据结构基础</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time datetime="2022-07-13T17:22:08.000Z" title="发表于 2022-07-14 01:22:08">2022-07-14</time></span></div><div class="content">1）SDS 简单动态字符串因为Redis是用C语言写的，在C中字符是固定分配的，如果下标越界就会爆缓冲区溢出，并且对于字符串的长度还必须遍历才可以获取。
那么在Redis中就寻求对字符串的实现进行改造，其实就是将字符串抽象成一个结构，用数组来存储各个字符，记录下字符串长度，空闲空间等信息，这样的结构就有利于后面数组的自动扩容。有点类似 Java 中的 String 对象。

优点：
① O(1)获取长度。在C中获取长度需要遍历整个字符串，这里由于有属性记录，O(1)即可；
② 避免缓冲区溢出。 因为字符串是动态变长的，不会存在越界溢出的危险；
③ 二进制安全。SDS的API均将输入信息作为二进制处理，可以保存信息原貌；
④ 减少修改字符串时的内存重分配。对于字符串的扩长采用预分配策略，如果修改后小于1MB则分配跟字符串长度一致的空闲空间，如果修改后大于1MB则分配1MB的空闲空间；对于字符串的缩短操作采用惰性释放的策略，不马上释放空间；
⑤ 兼容C的操作。提高函数复用性，减少代码冗余；
2）ZipList 压缩列表看名字也知道了，它的诞生就是为了尽可能地压缩使用的内存空间，在双向链表中 ...</div></div></div><div class="recent-post-item"><div class="recent-post-info no-cover"><a class="article-title" href="/2022/07/10/%E3%80%90RPC%E3%80%91%E5%9F%BA%E6%9C%AC%E7%BD%91%E7%BB%9C%E9%80%9A%E4%BF%A1%E6%A8%A1%E5%9E%8B/" title="【RPC】基本网络通信模型">【RPC】基本网络通信模型</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time datetime="2022-07-09T18:53:35.000Z" title="发表于 2022-07-10 02:53:35">2022-07-10</time></span></div><div class="content">1、传统 BIO 模型可以看到这里有两个阻塞点，一个是在accept时等待连接接入，一个是在read函数调用时，等待对方传输数据进而进行读取操作。因为有两个阻塞点的存在，这种通讯模型的效率不高，大多数情况都是处于阻塞等待。

BIO 的 B 代表的是阻塞，这种阻塞型的 IO 的特点是如果 read 调用时还没有数据到达会阻塞住等待，如果有数据到达网卡缓冲区，那么会先将数据由内核态转移到用户态，再传送给调用 read 方法的对象。

2、NIO1）第一阶段：将 accept 和 read 分为两个过程处理，accept 接收到请求之后开启一个新的线程去进行处理，read 操作发生在新线程中，不会影响到 accept 的接收，这里还不能说是严格意义上的 NIO，因为 read 在无数据到达时还是会一直阻塞住。

2）第二阶段：Java 中的 NIO 于 JDK4 引入，对应 java.nio 包，提供了 Channel , Selector，Buffer 等抽象。NIO 支持面向缓冲，基于通道的 I/O 操作方法。 当调用 read 函数没有发现目标方发送的数据时，会立即返回 -1，而并不 ...</div></div></div><div class="recent-post-item"><div class="recent-post-info no-cover"><a class="article-title" href="/2022/07/02/%E3%80%90JVM%E3%80%91%E7%B1%BB%E5%8A%A0%E8%BD%BD%E5%85%A8%E8%BF%87%E7%A8%8B%E7%AE%80%E8%AE%B0/" title="【JVM】类加载全过程简记">【JVM】类加载全过程简记</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time datetime="2022-07-01T18:24:51.000Z" title="发表于 2022-07-02 02:24:51">2022-07-02</time></span></div><div class="content">1、加载阶段如果是本地加载就是将java文件通过编译为class文件，之后将class文件的类相关静态信息写入方法区，在堆中创建一个Class对象用来当做访问方法区的一个入口，加载阶段实正常情况下是利用双亲委派模型来进行的。
2、验证阶段验证阶段主要是确保类的信息是符合jvm规范的，因为类的加载不只是本地加载class文件，还可以从流获取，因此这里需要做一番校验。
验证阶段由表及里，首先是文件格式的验证，确保带有魔数信息，并且确保jvm支持该版本的代码；第二步是元数据验证，主要是对字节码描述的信息进行语义分析，包括检测是否有final类被继承，是否有继承的父类（所有都要有Object父类）等；第三步是字节码验证，主要是通过数据流保证程序语义合法、符合逻辑；第四步是符号引用验证，这一步会发生在解析阶段，这也就是说这几个阶段实际上一个结束另一个开始的，而是交叉进行的，在这一步主要是检验符号引用到直接引用中间是否会出现问题，包括全类名能否找到指定的类，访问限定符有没有问题等，实际上这一步也不是必须的，如果你可以确保程序的引用转换不会出现问题，可以通过 -Xverify:none 来关闭这一步 ...</div></div></div><div class="recent-post-item"><div class="recent-post-info no-cover"><a class="article-title" href="/2022/06/28/%E3%80%90RPC%E3%80%91RPC%E5%AE%9E%E6%88%98%E4%B8%8E%E6%A0%B8%E5%BF%83%E7%9A%84%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/" title="【RPC】RPC实战与核心的学习笔记">【RPC】RPC实战与核心的学习笔记</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time datetime="2022-06-27T18:46:28.000Z" title="发表于 2022-06-28 02:46:28">2022-06-28</time></span></div><div class="content">1、一致性的选择强一致性要求相对会比较苛刻一些，相比之下，最终一致性才是系统设计中比较常用的一种策略，在系统的强健壮性/强一致性的选择下，应该根据需求去判断。
RPC的服务发现中，如果选用zk则可以达到强一致性的目的，但在服务量大的情况下容易造成节点不受控的宕机，因而如果在考虑系统的强健壮性情况下，可以选择使用消息总线机制来完成服务发现功能，采用异步推拉的模式来保证最终一致性，也即是舍弃CP选择AP。
推拉结合实际上就是对最终一致性的实践，新服务节点上线的时候向服务注册中心推送一个消息，告知服务中心有新节点上线了，但调用服务的节点并不马上去同步到消息，而是等待拉操作的发生，进而去同步节点的信息，这一过程最终总会实现一致，但不是强一致。
2、健康监测机制对于一个服务来说可能有三种状态，分别为健康状态、亚健康状态、死亡状态，这三种也就分别对应着正常服务、服务质量不佳、服务异常三种表现。一般的根据连接状态来判断服务的方式只能探测出服务是否异常，而对于服务质量不佳的情况是无法及时发现的，也就容易造成整体服务质量的下降。因此在常规的连接检测之外，还需要有具体的根据业务维度来做的服务质量检测，比如 ...</div></div></div><div class="recent-post-item"><div class="recent-post-info no-cover"><a class="article-title" href="/2022/06/23/%E3%80%90MySQL%E3%80%91%E7%AE%80%E5%8D%95%E8%AE%B0%E5%BD%95%E4%B8%80%E4%B8%8B-SQL-%E8%B0%83%E4%BC%98%E7%9A%84%E5%85%A5%E6%89%8B%E7%82%B9/" title="【MySQL】简单记录一下 SQL 调优的入手点">【MySQL】简单记录一下 SQL 调优的入手点</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time datetime="2022-06-22T18:57:04.000Z" title="发表于 2022-06-23 02:57:04">2022-06-23</time></span></div><div class="content">1、查询固定数目数据时需要加限制当业务可以保证查询时只有固定条数的数据时，需要在 sql 语句中加上 limit 限制，这样可以保证数据库在查询到指定条数的数据之后直接返回，而不用再做额外的 IO 遍历。
select id,name,price from course where id=10 limit 1;
2、联合索引的使用当 sql 语句涉及多个字段的筛选时，可以尝试按照一定的顺序建立联合索引，以便提高查询效率，这样比拆分多个字段的索引效率更高。同时建立联合索引需要避免索引失效的情况，包括最左前缀原则、联合索引中字段的范围查询。基于此也可以尝试对数据库中多个索引进行合并，当然这要基于业务的前提去做。
select id,name,price from course where name like &#39;张%&#39; and price=10; (name,price)
对于联合索引有时也可以利用到覆盖索引来减少回表的操作，例如上面这个语句，所有信息都在同一个联合索引树上，查询到数据无需回表，这样也会加快效率。
3、分页组件的count优化对于分页组件来说，一般流程需要先  ...</div></div></div><div class="recent-post-item"><div class="recent-post-info no-cover"><a class="article-title" href="/2022/06/20/%E3%80%90MySQL%E3%80%91%E7%B4%A2%E5%BC%95%E7%9A%84%E8%AE%BE%E7%BD%AE%E4%B8%8E%E7%B4%A2%E5%BC%95%E5%A4%B1%E6%95%88/" title="【MySQL】索引的设置与索引失效">【MySQL】索引的设置与索引失效</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time datetime="2022-06-19T17:57:15.000Z" title="发表于 2022-06-20 01:57:15">2022-06-20</time></span></div><div class="content">1、建索引与用索引建议建立索引的几个场景，需要根据业务需求进行权衡：

有唯一性的字段
频繁查询的字段
频繁进行group by 或 order by的字段
update或delete语句中where后带的字段
需要去重字段（distinct）
字段类型占用空间较小的（索引树占用空间也就会小）
对于长字符串的，使用其前缀建索引
区分度较高的字段

此外还有索引使用的几个注意事项：

使用最频繁的列放在联合索引的左边（最左前缀）
多字段尽量使用联合索引而非独立索引
一般索引不超过6个，这一块需要自行权衡

2、索引失效的场景1、不符合最左前缀原则对于联合索引或者是字符串索引会有最左前缀原则，如果对于表（a，b，c）中的索引（b，c），查询条件只为 c 的情况是不会走上这个索引树的。
2、计算、函数导致索引失效① 对查询字段进行运算会导致索引失效，例如：
1SELECT SQL_NO_CACHE id, stuno, NAME FROM student WHERE stuno+1 &#x3D; 900001; 

但如果把条件改为 stuno=900001-1 则可以走上索引。
② 对查询 ...</div></div></div><div class="recent-post-item"><div class="recent-post-info no-cover"><a class="article-title" href="/2022/06/17/%E3%80%90MySQL%E3%80%91%E7%B4%A2%E5%BC%95%E7%9A%84%E5%88%86%E7%B1%BB/" title="【MySQL】索引的分类">【MySQL】索引的分类</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time datetime="2022-06-16T17:55:25.000Z" title="发表于 2022-06-17 01:55:25">2022-06-17</time></span></div><div class="content">1、B+树基本形状如图，B+树上只有叶子节点才存放数据，其他节点只是索引/目录作用。

2、聚簇索引和非聚簇索引InnoDB 引擎中是索引组织表，因此主键索引所在的B+树也就是数据存储的地方，其中叶子节点存储着数据，其他节点中顺序存储着主键的值，方便进行二分查找，因此主键索引也可以称为聚簇索引；
其他的索引自然就是非聚簇索引，也称为二级索引。每建立一个二级索引，对应的就是在磁盘中多存储一颗B+树，二级索引中的叶子节点并不存放完整数据，而是只存储主键+索引字段。
3、回表和覆盖索引上面讲到了二级索引只存储主键和索引字段，那么当我们需要借助二级索引去查询第三个字段的时候，怎么办呢？这时候就需要再二级索引树上拿到主键值，之后根据主键值去主键索引树上查找第三个字段的信息，这个过程也称为回表操作。
回表是因为要查询第三个字段，导致会多一次访问B+树的开销，那么如果我们查询的只是索引字段+主键呢？又或者只是查询索引字段呢？这时候我们访问一遍二级索引树就可以得到需要的值，那么就无需回表，这种操作就叫做覆盖索引。
4、联合索引和最左前缀联合索引本质上也是一个二级索引，只不过索引字段为多个，并且严格按照 ...</div></div></div><div class="recent-post-item"><div class="recent-post-info no-cover"><a class="article-title" href="/2022/06/16/%E3%80%90MySQL%E3%80%91%E5%90%84%E7%A7%8D%E8%87%AA%E5%A2%9EID%E7%9A%84%E9%97%AE%E9%A2%98/" title="【MySQL】各种自增ID的问题">【MySQL】各种自增ID的问题</a><div class="article-meta-wrap"><span class="post-meta-date"><i class="far fa-calendar-alt"></i><span class="article-meta-label">发表于</span><time datetime="2022-06-16T13:53:46.000Z" title="发表于 2022-06-16 21:53:46">2022-06-16</time></span></div><div class="content">1、自增 id 的存储与生成在 MyISAM 中自增 id 值会存储在一个数据文件中，那么每次只需要读取该文件即可获取自增 id 信息，这也确保了自增 id 的持久化。
在 MySQL 8.0之前， InnoDB 将自增 id 的值存储在内存中，并不具备持久化的能力，而每次重启之后都取表中的 MAX+1 作为自增 id；在 MySQL 8.0之后将自增id写在 redo log 日志中，保证了持久化。
2、自增 id 不连续的情况1）第一种情况：
可以看到，如果插入值利用到了自增id，那么是会先获取自增id，再执行自增，最后再执行语句，那么如果语句遇到唯一键错误等就会停止执行，那么这条数据也就没了，自增值却不能恢复，这将导致自增值的空洞。
2）第二种情况：假如在事务执行过程中，插入语句成功通过检查准备执行，事务回滚了，那么也会导致自增值的空洞，原因和第一种情况类似，主要在于语句会回滚但自增值并不会回滚。
3）第三种情况：对于批量插入数据的语句，MySQL 有一个批量申请自增 id 的策略：
① 语句执行过程中，第一次申请自增 id，会分配 1 个；
② 1 个用完以后，这个语句第二次申 ...</div></div></div><nav id="pagination"><div class="pagination"><span class="page-number current">1</span><a class="page-number" href="/page/2/#content-inner">2</a><span class="space">&hellip;</span><a class="page-number" href="/page/5/#content-inner">5</a><a class="extend next" rel="next" href="/page/2/#content-inner"><i class="fas fa-chevron-right fa-fw"></i></a></div></nav></div><div class="aside-content" id="aside-content"><div class="card-widget card-info"><div class="card-info-avatar is-center"><img class="avatar-img" src="/img/avatar.jpg" onerror="this.onerror=null;this.src='/img/friend_404.gif'" alt="avatar"/><div class="author-info__name">h0ss</div><div class="author-info__description">一个苦逼后端仔的学习记录</div></div><div class="card-info-data"><div class="card-info-data-item is-center"><a href="/archives/"><div class="headline">文章</div><div class="length-num">51</div></a></div><div class="card-info-data-item is-center"><a href="/tags/"><div class="headline">标签</div><div class="length-num">14</div></a></div></div><a class="button--animated" id="card-info-btn" target="_blank" rel="noopener" href="https://gitee.com/h0ss"><i class="fab fa-github"></i><span>Gitee仓库</span></a></div><div class="card-widget card-announcement"><div class="item-headline"><i class="fas fa-bullhorn card-announcement-animation"></i><span>公告</span></div><div class="announcement_content">Java后端技术栈语雀文档：https://www.yuque.com/oliver-wdtb1/java</div></div><div class="sticky_layout"><div class="card-widget card-recent-post"><div class="item-headline"><i class="fas fa-history"></i><span>最新文章</span></div><div class="aside-list"><div class="aside-list-item no-cover"><div class="content"><a class="title" href="/2022/11/16/%E7%BB%99%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AE%E6%8F%90%E4%BA%86%E4%B8%AAPR/" title="给开源项目提了个PR">给开源项目提了个PR</a><time datetime="2022-11-15T17:28:40.000Z" title="发表于 2022-11-16 01:28:40">2022-11-16</time></div></div><div class="aside-list-item no-cover"><div class="content"><a class="title" href="/2022/09/03/%E3%80%90MySQL%E3%80%91InnoDB%E7%9A%84%E8%A1%8C%E6%A0%BC%E5%BC%8F/" title="【MySQL】InnoDB的行格式">【MySQL】InnoDB的行格式</a><time datetime="2022-09-02T18:17:38.000Z" title="发表于 2022-09-03 02:17:38">2022-09-03</time></div></div><div class="aside-list-item no-cover"><div class="content"><a class="title" href="/2022/08/21/%E3%80%90Debug%E3%80%91bitField-%E5%BC%95%E5%8F%91%E7%9A%84%E6%A0%88%E6%BA%A2%E5%87%BA%E6%8E%92%E9%94%99%E8%AE%B0/" title="【Debug】bitField 引发的栈溢出排错记">【Debug】bitField 引发的栈溢出排错记</a><time datetime="2022-08-20T18:10:40.000Z" title="发表于 2022-08-21 02:10:40">2022-08-21</time></div></div><div class="aside-list-item no-cover"><div class="content"><a class="title" href="/2022/07/16/%E3%80%90RPC%E3%80%91%E8%AF%A6%E8%A7%A3SPI%E6%9C%BA%E5%88%B6/" title="【RPC】详解SPI机制">【RPC】详解SPI机制</a><time datetime="2022-07-15T18:51:57.000Z" title="发表于 2022-07-16 02:51:57">2022-07-16</time></div></div><div class="aside-list-item no-cover"><div class="content"><a class="title" href="/2022/07/14/%E3%80%90Redis%E3%80%91%E9%87%8D%E8%A6%81%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%9F%BA%E7%A1%80/" title="【Redis】重要数据结构基础">【Redis】重要数据结构基础</a><time datetime="2022-07-13T17:22:08.000Z" title="发表于 2022-07-14 01:22:08">2022-07-14</time></div></div></div></div><div class="card-widget card-tags"><div class="item-headline"><i class="fas fa-tags"></i><span>标签</span></div><div class="card-tag-cloud"><a href="/tags/AppCube/" style="font-size: 1.1em; color: #999">AppCube</a> <a href="/tags/JVM/" style="font-size: 1.33em; color: #99a2af">JVM</a> <a href="/tags/Java/" style="font-size: 1.5em; color: #99a9bf">Java</a> <a href="/tags/LeetCode/" style="font-size: 1.21em; color: #999ea4">LeetCode</a> <a href="/tags/Linux/" style="font-size: 1.39em; color: #99a4b4">Linux</a> <a href="/tags/MySQL/" style="font-size: 1.44em; color: #99a7ba">MySQL</a> <a href="/tags/Mybatis/" style="font-size: 1.1em; color: #999">Mybatis</a> <a href="/tags/RPC/" style="font-size: 1.27em; color: #99a0a9">RPC</a> <a href="/tags/Redis/" style="font-size: 1.27em; color: #99a0a9">Redis</a> <a href="/tags/SQL/" style="font-size: 1.1em; color: #999">SQL</a> <a href="/tags/Spring/" style="font-size: 1.33em; color: #99a2af">Spring</a> <a href="/tags/%E6%AD%A3%E5%88%99%E8%A1%A8%E8%BE%BE%E5%BC%8F/" style="font-size: 1.1em; color: #999">正则表达式</a> <a href="/tags/%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86/" style="font-size: 1.1em; color: #999">组成原理</a> <a href="/tags/%E8%AE%A1%E7%BD%91/" style="font-size: 1.16em; color: #999b9e">计网</a></div></div><div class="card-widget card-archives"><div class="item-headline"><i class="fas fa-archive"></i><span>归档</span><a class="card-more-btn" href="/archives/" title="查看更多">
    <i class="fas fa-angle-right"></i></a></div><ul class="card-archive-list"><li class="card-archive-list-item"><a class="card-archive-list-link" href="/archives/2022/11/"><span class="card-archive-list-date">十一月 2022</span><span class="card-archive-list-count">1</span></a></li><li class="card-archive-list-item"><a class="card-archive-list-link" href="/archives/2022/09/"><span class="card-archive-list-date">九月 2022</span><span class="card-archive-list-count">1</span></a></li><li class="card-archive-list-item"><a class="card-archive-list-link" href="/archives/2022/08/"><span class="card-archive-list-date">八月 2022</span><span class="card-archive-list-count">1</span></a></li><li class="card-archive-list-item"><a class="card-archive-list-link" href="/archives/2022/07/"><span class="card-archive-list-date">七月 2022</span><span class="card-archive-list-count">4</span></a></li><li class="card-archive-list-item"><a class="card-archive-list-link" href="/archives/2022/06/"><span class="card-archive-list-date">六月 2022</span><span class="card-archive-list-count">10</span></a></li><li class="card-archive-list-item"><a class="card-archive-list-link" href="/archives/2022/05/"><span class="card-archive-list-date">五月 2022</span><span class="card-archive-list-count">1</span></a></li><li class="card-archive-list-item"><a class="card-archive-list-link" href="/archives/2022/04/"><span class="card-archive-list-date">四月 2022</span><span class="card-archive-list-count">1</span></a></li><li class="card-archive-list-item"><a class="card-archive-list-link" href="/archives/2022/03/"><span class="card-archive-list-date">三月 2022</span><span class="card-archive-list-count">1</span></a></li></ul></div><div class="card-widget card-webinfo"><div class="item-headline"><i class="fas fa-chart-line"></i><span>网站资讯</span></div><div class="webinfo"><div class="webinfo-item"><div class="item-name">文章数目 :</div><div class="item-count">51</div></div><div class="webinfo-item"><div class="item-name">已运行时间 :</div><div class="item-count" id="runtimeshow" data-publishDate="2021-02-14T16:00:00.000Z"></div></div><div class="webinfo-item"><div class="item-name">本站总字数 :</div><div class="item-count">129.9k</div></div><div class="webinfo-item"><div class="item-name">最后更新时间 :</div><div class="item-count" id="last-push-date" data-lastPushDate="2022-11-15T17:31:31.795Z"></div></div></div></div></div></div></main><footer id="footer"><div id="footer-wrap"><div class="framework-info"><span>框架 </span><a target="_blank" rel="noopener" href="https://hexo.io">Hexo</a><span class="footer-separator">|</span><span>主题 </span><a target="_blank" rel="noopener" href="https://github.com/jerryc127/hexo-theme-butterfly">Butterfly</a></div></div></footer></div><div id="rightside"><div id="rightside-config-hide"><button id="darkmode" type="button" title="浅色和深色模式转换"><i class="fas fa-adjust"></i></button><button id="hide-aside-btn" type="button" title="单栏和双栏切换"><i class="fas fa-arrows-alt-h"></i></button></div><div id="rightside-config-show"><button id="rightside_config" type="button" title="设置"><i class="fas fa-cog fa-spin"></i></button><button id="go-up" type="button" title="回到顶部"><i class="fas fa-arrow-up"></i></button></div></div><div><script src="/js/utils.js"></script><script src="/js/main.js"></script><div class="js-pjax"></div><script defer="defer" id="fluttering_ribbon" mobile="false" src="https://cdn.jsdelivr.net/npm/butterfly-extsrc@1/dist/canvas-fluttering-ribbon.min.js"></script><script id="canvas_nest" defer="defer" color="0,0,255" opacity="0.7" zIndex="-1" count="99" mobile="false" src="https://cdn.jsdelivr.net/npm/butterfly-extsrc@1/dist/canvas-nest.min.js"></script><script id="click-heart" src="https://cdn.jsdelivr.net/npm/butterfly-extsrc@1/dist/click-heart.min.js" async="async" mobile="false"></script><script id="click-show-text" src="https://cdn.jsdelivr.net/npm/butterfly-extsrc@1/dist/click-show-text.min.js" data-mobile="false" data-text="爱国,敬业,诚信,友善,自由,平等,公正,法治,富强,民主,文明,和谐" data-fontsize="16px" data-random="false" async="async"></script></div></body></html>